home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Disc to the Future 2
/
Disc to the Future Part II Programmer's Reference (Wayzata Technology)(6013)(1992).bin
/
MAC
/
THINKC
/
TCL1
/
CDICTION
/
CDICTION.C
next >
Wrap
Text File
|
1990-01-12
|
8KB
|
306 lines
/********************************************************************
CDictionary.c
see header for information
SUPERCLASS = CCollection
********************************************************************/
#include "CDictionary.h"
#include "CDataFile.h"
#include "CApplication.h"
#include "CError.h"
#include "TBUtilities.h"
#define kMintableSize 64L /* minimum table size */
/* macro to calculate address of a bucket in the hash table
can't use C arrays because entry size is determined
at runtime */
#define ASSOCIATION( bucketNum) \
((tAssociationPtr) (*table + ((Int32)bucketNum * slotSize)))
#define EMPTY ((void*) 0L)
#define DELETED ((void*) -1L)
#define VACANT( assocPtr) \
((assocPtr->value == EMPTY)||(assocPtr->value == DELETED))
#define NOT_FOUND (-1L)
extern CApplication *gApplication;
extern CError *gError;
/********************************************************************/
Boolean CDictionary::IDictionary( Int16 keySize, MapProc map, CompareProc compare,
Int32 initialSize)
/*
initialize a Dictionary, return false if no error.
*/
{
Int32 sizeNeeded;
register Int16 power2;
register Int32 bits;
CCollection::ICollection();
/* get initial table size */
this->map = map;
this->compare = compare;
this->keySize = keySize;
this->slotSize = keySize + sizeof( CObject*);
/* tableSize must be power of 2 >= kMinTableSize */
initialSize = MAX( initialSize, kMintableSize);
/* find greatest power of 2 <= initialSize */
power2 = 0; bits = initialSize;
while (bits >>= 1) power2++;
/* if initialSize was power of 2 use it, else get next highest */
tableSize = initialSize == 1 << power2 ? initialSize : 1 << (power2 + 1);
slotsLeft = tableSize;
/* calculate size of hash table and allocate the memory */
sizeNeeded = tableSize * (Int32) slotSize;
gApplication->RequestMemory( FALSE, TRUE);
table = NewHandleClear( sizeNeeded);
gApplication->RequestMemory( FALSE, FALSE);
if (!table) return TRUE;
MoveHHi( table);
return FALSE;
} /* CDictionary::IDictionary */
/********************************************************************/
void CDictionary::Add( void *key, CObject *value)
{
Int32 hash, curr;
/* always leave at least one empty slot as sentinel */
if (slotsLeft <= 1) MoreSlots();
/* map key to value and do simple mod to get table index */
curr = hash = map( key) & (tableSize -1);
while( !VACANT(ASSOCIATION(curr)))
{
/* if the key is already present then replace its
value and return */
if(compare( key, (void*) ASSOCIATION(curr)->key) )
{
ASSOCIATION(curr)->value = value;
return;
}
if (++curr == tableSize) curr = 0; /* linear probing with wraparound */
}
/* curr now points to a vacant slot */
ASSOCIATION(curr)->value = value;
BlockMove( key, ASSOCIATION(curr)->key, keySize);
numItems++;
slotsLeft--;
} /* CDictionary::Add */
/********************************************************************/
/* iterator for dictionary to add */
static void DICT_AddAssoc( tAssociationPtr anAssoc, Int32 targetDict)
{
((CDictionary*) targetDict)->Add( anAssoc->key, anAssoc->value);
} /* DICT_AddAssoc */
void CDictionary::AddAll( CDictionary *aDictionary)
{
aDictionary->DoForEach1( DICT_AddAssoc, (Int32)this);
} /* CDictionary::AddAll */
/********************************************************************/
void CDictionary::Remove( void *key)
{
Int32 index = _lookup( key);
if (index != NOT_FOUND)
{
ASSOCIATION( index)->value = DELETED;
numItems--;
}
} /* CDictionary::Remove */
/********************************************************************/
Boolean CDictionary::IncludesKey( void *key)
{
return (_lookup( key) != NOT_FOUND);
} /* CDictionary::IncludesKey */
/********************************************************************/
Boolean CDictionary::IncludesValue( CObject *anObject)
{
Int32 i;
tAssociationPtr assoc;
for (i = 0; i < tableSize; i++)
{
assoc = ASSOCIATION(i);
if (!VACANT( assoc))
{
if (anObject == assoc->value)
return TRUE;
}
}
return FALSE;
} /* CDictionary::IncludesValue */
/********************************************************************/
void CDictionary::DoForEach( DictIterator actionProc)
{
Int32 i;
tAssociationPtr assoc;
SignedByte hState;
/* since we pass the iterator a pointer to our data,
it is safer to lock the table down so the pointer
remains valid */
MoveHHi( table);
hState = HGetState( table);
HLock( table);
for (i = 0; i < tableSize; i++)
{
assoc = ASSOCIATION(i);
if (!VACANT( assoc))
actionProc( assoc);
}
HSetState( table, hState);
} /* CDictionary::DoForEach */
/********************************************************************/
void CDictionary::DoForEach1( DictIterator1 actionProc, Int32 aParam)
{
Int32 i;
tAssociationPtr assoc;
SignedByte hState;
MoveHHi( table);
hState = HGetState( table);
HLock( table);
for (i = 0; i < tableSize; i++)
{
assoc = ASSOCIATION(i);
if (!VACANT( assoc))
actionProc( assoc, aParam);
}
HSetState( table, hState);
} /* CDictionary::DoForEach1 */
/********************************************************************/
CObject *CDictionary::Lookup( void *key)
{
Int32 index = _lookup( key);
return( index == NOT_FOUND? NIL : ASSOCIATION( index)->value);
} /* CDictionary::Lookup */
/********************************************************************/
Int32 CDictionary::_lookup( void *key)
/*
private routine to lookup a key in the hash table.
Given a key, either returns its index (a positive long),
or NOT_FOUND.
*/
{ register Int32 curr;
curr = map( key) & (tableSize -1);
while(ASSOCIATION(curr)->value != EMPTY &&
(ASSOCIATION(curr)->value == DELETED ? 1:!compare( key,ASSOCIATION(curr)->key)))
{
if (++curr == tableSize) curr = 0;
}
return (ASSOCIATION(curr)->value == EMPTY ? NOT_FOUND : curr);
} /* CDictionary::_lookup */
/********************************************************************/
CObject *CDictionary::Copy( void)
{
CDictionary *newDict = (CDictionary *) inherited::Copy();
Handle tableCopy = table;
newDict->table = NIL;
HandToHand( &tableCopy);
if (!gError->CheckOSError( MemError()))
{
newDict->Dispose();
return NIL;
}
MoveHHi( tableCopy);
newDict->table = tableCopy;
newDict->itsFile = NIL;
return newDict;
} /* CDictionary::Copy */
/********************************************************************/
void CDictionary::MoreSlots( void)
/*
called when we need to grow the table.
*/
{ CDictionary *tmpDict;
Int32 newSize;
tmpDict = (CDictionary*) Copy();/* make temporary copy of dictionary */
if (tmpDict)
{
tableSize <<= 1;
newSize = tableSize * slotSize;
DisposHandle( table);
gApplication->RequestMemory( FALSE, TRUE);
table = NewHandleClear( newSize);
gApplication->RequestMemory( FALSE, FALSE);
if (!table) gError->SevereMacError( memFullErr);
MoveHHi( table);
numItems = 0;
slotsLeft = tableSize;
AddAll( tmpDict);
tmpDict->Dispose();
}
else gError->SevereMacError( memFullErr);
} /* CDictionary::MoreSlots */
/********************************************************************/
void CDictionary::Dispose( void)
{
if (table) DisposHandle( table);
inherited::Dispose();
} /* CDictionary::Dispose */
/********************************************************************/
void CDictionary::DisposeAll( void)
{
DisposeItems();
Dispose();
} /* CDictionary::DisposeAll */
/********************************************************************/
/* iterator for disposing items */
static void DICT_DisposeItems( tAssociationPtr anAssoc)
{
if (anAssoc->value) anAssoc->value->Dispose();
} /* DICT_DisposeItems */
void CDictionary::DisposeItems( void)
{
DoForEach( DICT_DisposeItems);
numItems = 0;
} /* CDictionary::DisposeItems */
/********************************************************************/